package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"hanmoon-product/common"
	"hanmoon-product/datamodels"
	"hanmoon-product/encrypt"
	RabbitMQ "hanmoon-product/rabbitmq"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"sync"
)

//设置集群地址 ，最好内网IP
var hostArray = []string{"127.0.0,1", "17.0.0.1"}

var localHost = ""
var port = "8083"

//数量控制接口，内网ip
var GetOneIp = "127.0.0.1"

var GetOnePort = "8084"

var hashConsistent *common.Consistent

//rabbitMQ
var rabbitMqValiddate *RabbitMQ.RabbitMQ

//存放控制信息
type AccessControl struct {
	//用来存放用户想要放的信息
	sourcesArray map[int]interface{}
	sync.RWMutex
}

var accessControl = &AccessControl{sourcesArray: make(map[int]interface{})}

func (m *AccessControl) GetNewRecord(uid int) interface{} {
	m.RWMutex.RLock()
	defer m.RWMutex.Unlock()
	data := m.sourcesArray[uid]
	return data
}

func (m *AccessControl) SetNewRecord(uid int) {
	m.RWMutex.Lock()
	defer m.RWMutex.Unlock()
	m.sourcesArray[uid] = "hello world"
}

func (m *AccessControl) GetDistriButedRight(req *http.Request) bool {
	uid, err := req.Cookie("uid")
	if err != nil {
		return false
	}
	hostRequest, err := hashConsistent.Get(uid.Value)
	if err != nil {
		return false
	}
	if hostRequest == localHost {
		//执行本季数据读取
		return m.GetDateFromMap(uid.Value)
	} else {
		//	充当代理访问数据返回结果
		return GetDataFromOtherMap(hostRequest, req)
	}
}

//获取其他节点处理结果
func GetDataFromOtherMap(host string, request *http.Request) bool {

	hostUrl := "http://" + host + ":" + port + "/checkRight"
	response, body, err := GetCurl(hostUrl, request)
	if err != nil {
		return false
	}
	if response.StatusCode == 200 {
		if string(body) == "true" {
			return true
		} else {
			return false
		}
	}
	return false
}

//获取本季map，处理业务逻辑
func (m *AccessControl) GetDateFromMap(uid string) (isOK bool) {
	//uidInt, err := strconv.Atoi(uid)
	//if err != nil {
	//	return false
	//}
	//data := m.GetNewRecord(uidInt)
	//
	////执行逻辑判断
	//if data != nil {
	//	return true
	//}
	return true
}

func main() {
	//负载均衡器设置
	//一致性哈希算法
	hashConsistent = common.NewConsistent()
	//采用一致性哈希算法，添加节点
	for _, v := range hostArray {
		hashConsistent.Add(v)
	}

	ip, err := common.GetIntranceIP()
	if err != nil {
		fmt.Println(err)
	}
	localHost = ip
	fmt.Println(localHost)

	rabbitMqValiddate = RabbitMQ.NewRabbitSimple("hanmoonProduct")
	defer rabbitMqValiddate.Destory()

	//设置静态文件目录
	http.Handle("/html/", http.StripPrefix("/html/",
		http.FileServer(http.Dir("./fronted/web/htmlProductShow"))))
	//设置资源目录
	http.Handle("/public", http.StripPrefix("/public",
		http.FileServer(http.Dir("./fronted/web/public"))))

	//1.过滤器
	filter := common.NewFilter()
	//注册拦截器
	filter.RegisterFilterUri("/check", Auth)
	filter.RegisterFilterUri("/checkRight", Auth)
	//2.启动 服务
	http.HandleFunc("/check", filter.Handle(Check))
	http.HandleFunc("/checkRight", filter.Handle(CheckRight))
	//启动 服务
	http.ListenAndServe(":8083", nil)
}

//模拟请求
func GetCurl(hostUrl string, request *http.Request) (response *http.Response, body []byte, err error) {
	//获取uid
	uidPre, err := request.Cookie("uid")
	if err != nil {
		return
	}
	//获取sign
	uidSign, err := request.Cookie("sign")
	if err != nil {
		return
	}
	client := &http.Client{}
	req, err := http.NewRequest("GET", hostUrl, nil)
	if err != nil {
		return
	}

	//手动指定，排查多余Cookie
	cookieUid := &http.Cookie{Name: "uid", Value: uidPre.Value, Path: "/"}
	cookieSign := &http.Cookie{Name: "sign", Value: uidSign.Value, Path: "/"}

	req.AddCookie(cookieUid)
	req.AddCookie(cookieSign)

	response, err = client.Do(req)
	defer response.Body.Close()
	if err != nil {
		return
	}
	body, err = ioutil.ReadAll(response.Body)

	return
}

func CheckRight(w http.ResponseWriter, r *http.Request) {
	right := accessControl.GetDistriButedRight(r)
	if right == false {
		w.Write([]byte("false"))
		return
	}
	w.Write([]byte("true"))
	return
}

//执行逻辑
func Check(w http.ResponseWriter, r *http.Request) {
	//执行
	fmt.Println("执行check!")

	query, err := url.ParseQuery(r.URL.RawQuery)
	if err != nil || len(query["productID"]) <= 0 {
		w.Write([]byte("false"))
		return
	}
	productString := query["productID"][0]
	fmt.Println(productString)
	//获取用户Cookie
	userCookie, err := r.Cookie("uid")
	if err != nil {
		w.Write([]byte("false"))
		return
	}
	//1.分布式权限验证
	right := accessControl.GetDistriButedRight(r)
	if right == false {
		w.Write([]byte("false"))
	}
	//2.获取数量控制,防止超卖
	hostUrl := "http://" + GetOneIp + ":" + GetOnePort + "/getOne"
	curl, body, err := GetCurl(hostUrl, r)
	if err != nil {
		w.Write([]byte("false"))
		return
	}
	if curl.StatusCode == 200 {
		if string(body) == "true" {
			//整和下单
			//获取商品ID
			productID, err := strconv.ParseInt(productString, 10, 64)
			if err != nil {
				w.Write([]byte("false"))
				return
			}
			//获取用户ID
			userID, err := strconv.ParseInt(userCookie.Value, 10, 64)
			if err != nil {
				w.Write([]byte("false"))
				return
			}
			message := datamodels.NewMessage(userID, productID)
			//类型转换
			byteMessage, err := json.Marshal(message)
			if err != nil {
				w.Write([]byte("false"))
				return
			}
			err = rabbitMqValiddate.PulishSimple(string(byteMessage))
			if err != nil {
				w.Write([]byte("false"))
				return
			}
			w.Write([]byte("true"))
			return
		}
	}
	w.Write([]byte("false"))
	return
}

func checkUserInfo(r *http.Request) error {
	//获取uid cookie
	uidCookie, err := r.Cookie("uid")
	if err != nil {
		return errors.New("用户uid cookir获取失败")
	}
	//获取用户加密串
	cookie, err := r.Cookie("sign")
	if err != nil {
		return errors.New("用户uid cookie加密串获取失败")
	}

	//加密串解密
	code, err := encrypt.DePwdCode(cookie.Value)
	if err != nil {
		return errors.New("加密串被改")
	}

	fmt.Println("用户比对")
	fmt.Println("uid" + uidCookie.Value)
	fmt.Println("解密后用户id" + string(code))

	if checkInfo(uidCookie.Value, string(code)) {
		return nil
	}
	return errors.New("身份校验失败")
}

func checkInfo(checkStr string, signStr string) bool {
	if checkStr == signStr {
		return true
	}
	return false
}

//统一验证拦截器
func Auth(w http.ResponseWriter, r *http.Request) error {
	return nil
}
